sync w/ head.
*/
cpu_init();
}
-
-
- /*
- * install_safe_pf_handler / install_normal_pf_handler:
- *
- * These are used within the failsafe_callback handler in entry.S to avoid
- * taking a full page fault when reloading FS and GS. This is because FS and
- * GS could be invalid at pretty much any point while Xen Linux executes (we
- * don't set them to safe values on entry to the kernel). At *any* point Xen
- * may be entered due to a hardware interrupt --- on exit from Xen an invalid
- * FS/GS will cause our failsafe_callback to be executed. This could occur,
- * for example, while the mmmu_update_queue is in an inconsistent state. This
- * is disastrous because the normal page-fault handler touches the update
- * queue!
- *
- * Fortunately, within the failsafe handler it is safe to force DS/ES/FS/GS
- * to zero if they cannot be reloaded -- at this point executing a normal
- * page fault would not change this effect. The safe page-fault handler
- * ensures this end result (blow away the selector value) without the dangers
- * of the normal page-fault handler.
- *
- * NB. Perhaps this can all go away after we have implemented writable
- * page tables. :-)
- */
-
- asmlinkage void do_safe_page_fault(struct pt_regs *regs,
- unsigned long error_code,
- unsigned long address)
- {
- if (!fixup_exception(regs))
- die("Unhandleable 'safe' page fault!", regs, error_code);
- }
-
- unsigned long install_safe_pf_handler(void)
- {
- static trap_info_t safe_pf[] = {
- { 14, 0, __KERNEL_CS, (unsigned long)safe_page_fault },
- { 0, 0, 0, 0 }
- };
- unsigned long flags;
- local_irq_save(flags);
- HYPERVISOR_set_trap_table(safe_pf);
- return flags; /* This is returned in %%eax */
- }
-
- __attribute__((regparm(3))) /* This function take its arg in %%eax */
- void install_normal_pf_handler(unsigned long flags)
- {
- static trap_info_t normal_pf[] = {
- { 14, 0, __KERNEL_CS, (unsigned long)page_fault },
- { 0, 0, 0, 0 }
- };
- HYPERVISOR_set_trap_table(normal_pf);
- local_irq_restore(flags);
- }
+
+int smp_trap_init(trap_info_t *trap_ctxt)
+{
+ trap_info_t *t = trap_table;
+
+ for (t = trap_table; t->address; t++) {
+ trap_ctxt[t->vector].flags = t->flags;
+ trap_ctxt[t->vector].cs = t->cs;
+ trap_ctxt[t->vector].address = t->address;
+ }
+ return SYSCALL_VECTOR;
+}
void __init init_IRQ(void)
{
int i;
+ int cpu;
+ irq_ctx_init(0);
+
spin_lock_init(&irq_mapping_update_lock);
- /* No VIRQ -> IRQ mappings. */
- for ( i = 0; i < NR_VIRQS; i++ )
- virq_to_irq[i] = -1;
+ for ( cpu = 0; cpu < NR_CPUS; cpu++ ) {
+ /* No VIRQ -> IRQ mappings. */
+ for ( i = 0; i < NR_VIRQS; i++ )
+ per_cpu(virq_to_irq, cpu)[i] = -1;
+ }
/* No event-channel -> IRQ mappings. */
for ( i = 0; i < NR_EVENT_CHANNELS; i++ )
* within a page table are directly modified. Thus, the following
* hook is made available.
*/
- #ifdef CONFIG_XEN_WRITABLE_PAGETABLES
+ #define set_pte_batched(pteptr, pteval) \
+ queue_l1_entry_update(pteptr, (pteval).pte_low)
++
+#ifdef CONFIG_SMP
+#define set_pte(pteptr, pteval) xen_l1_entry_update(pteptr, (pteval).pte_low)
+#if 0
+do { \
+ (*(pteptr) = pteval); \
+ HYPERVISOR_xen_version(0); \
+} while (0)
+#endif
+#define set_pte_atomic(pteptr, pteval) set_pte(pteptr, pteval)
+#else
#define set_pte(pteptr, pteval) (*(pteptr) = pteval)
- #define set_pte_atomic(pteptr, pteval) (*(pteptr) = pteval)
- #else
- #define set_pte(pteptr, pteval) xen_l1_entry_update(pteptr, (pteval).pte_low)
- #define set_pte_atomic(pteptr, pteval) xen_l1_entry_update(pteptr, (pteval).pte_low)
- #endif
+ #define set_pte_atomic(pteptr, pteval) set_pte(pteptr,pteval)
+#endif
/*
* (pmds are folded into pgds so this doesn't get actually called,
* but the define is needed for a generic inline function.)
{
unsigned long sstat, spte, pte, *ptep, l1va;
l1_pgentry_t *sl1e = NULL, *pl1e, ol1e, nl1e;
- l2_pgentry_t *pl2e, nl2e;
+ l2_pgentry_t *pl2e;
int i, cpu = smp_processor_id();
- struct domain *d = current;
+ struct exec_domain *ed = current;
+ struct domain *d = ed->domain;
l1va = ptwr_info[cpu].ptinfo[which].l1va;
ptep = (unsigned long *)&linear_pg_table[l1va>>PAGE_SHIFT];
* STEP 3. Reattach the L1 p.t. page into the current address space.
*/
- if ( (which == PTWR_PT_ACTIVE) && likely(!d->mm.shadow_mode) )
+ if ( (which == PTWR_PT_ACTIVE) && likely(!ed->mm.shadow_mode) )
{
pl2e = &linear_l2_table[ptwr_info[cpu].ptinfo[which].l2_idx];
- nl2e = mk_l2_pgentry(l2_pgentry_val(*pl2e) | _PAGE_PRESENT);
- update_l2e(pl2e, *pl2e, nl2e);
+ *pl2e = mk_l2_pgentry(l2_pgentry_val(*pl2e) | _PAGE_PRESENT);
}
/*
/* Write page fault handler: check if guest is trying to modify a PTE. */
int ptwr_do_page_fault(unsigned long addr)
{
- unsigned long pte, pfn;
+ unsigned long pte, pfn, l2e;
struct pfn_info *page;
- l2_pgentry_t *pl2e, nl2e;
+ l2_pgentry_t *pl2e;
int which, cpu = smp_processor_id();
u32 l2_idx;
+ struct domain *d = current->domain;
+ LOCK_BIGLOCK(d);
/*
* Attempt to read the PTE that maps the VA being accessed. By checking for
* PDE validity in the L2 we avoid many expensive fixups in __get_user().
/* Get the L2 index at which this L1 p.t. is always mapped. */
l2_idx = page->u.inuse.type_info & PGT_va_mask;
if ( unlikely(l2_idx >= PGT_va_unknown) )
+ {
+ UNLOCK_BIGLOCK(d);
domain_crash(); /* Urk! This L1 is mapped in multiple L2 slots! */
+ }
l2_idx >>= PGT_va_shift;
-
+
+ if ( l2_idx == (addr >> L2_PAGETABLE_SHIFT) )
+ {
+ MEM_LOG("PTWR failure! Pagetable maps itself at %08lx\n", addr);
+ domain_crash();
+ }
+
/*
* Is the L1 p.t. mapped into the current address space? If so we call it
* an ACTIVE p.t., otherwise it is INACTIVE.
/* For safety, disconnect the L1 p.t. page from current space. */
if ( (which == PTWR_PT_ACTIVE) && likely(!current->mm.shadow_mode) )
{
- nl2e = mk_l2_pgentry(l2_pgentry_val(*pl2e) & ~_PAGE_PRESENT);
- update_l2e(pl2e, *pl2e, nl2e);
+ *pl2e = mk_l2_pgentry(l2e & ~_PAGE_PRESENT);
+#if 0
flush_tlb(); /* XXX Multi-CPU guests? */
+#else
+ flush_tlb_all();
+#endif
}
/* Temporarily map the L1 page, and make a copy of it. */